home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The World of Computer Software
/
The World of Computer Software.iso
/
srcuc.zip
/
DOSCONIO.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-05-05
|
13KB
|
466 lines
/* -*-C-*-
$Header: /scheme/dos386/microcode/RCS/dosconio.c,v 1.1 1992/05/05 06:55:13 jinx Exp $
Copyright (c) 1992 Massachusetts Institute of Technology
This material was developed by the Scheme project at the Massachusetts
Institute of Technology, Department of Electrical Engineering and
Computer Science. Permission to copy this software, to redistribute
it, and to use it for any purpose is granted, subject to the following
restrictions and understandings.
1. Any copy made of this software must include this copyright notice
in full.
2. Users of this software agree to make their best efforts (a) to
return to the MIT Scheme project any improvements or extensions that
they make, so that these may be included in future releases; and (b)
to inform MIT of noteworthy uses of this software.
3. All materials developed as a consequence of the use of this
software shall duly acknowledge such use, in accordance with the usual
standards of acknowledging credit in academic research.
4. MIT has made no warrantee or representation that the operation of
this software will be error-free, and MIT is under no obligation to
provide any services, by way of maintenance, update, or otherwise.
5. In conjunction with products arising from the use of this material,
there shall be no use of the name of the Massachusetts Institute of
Technology nor of any adaptation thereof in any advertising,
promotional, or sales literature without prior written consent from
MIT in each case. */
/* Console I/O supplement */
#include "scheme.h"
#include "prims.h"
#include "msdos.h"
#include "dosio.h"
#include "dosscan.h"
#include "dossys.h"
#include "intrpt.h"
/* This is really not set up to include Scheme level headers, so we
fake them here. */
extern long
IntCode, /* Interrupts requesting */
IntEnb; /* Interrupts enabled */
#ifdef __STDC__
#define fileno(fp) ((fp)->_file)
#endif
#define CONIO_BUFFER_SIZE (1024)
#define TYPEAHEAD_BUFFER_SIZE (1024)
#define System_Error_Reset() \
(errno = 0)
#define System_Error_Return(err) \
{ \
errno = err; \
return -1; \
}
/* Characters are kept in the typeahead_buffer before read is called,
in the key_buffer before return is pressed, and in the line_buffer
before the line is read.
*/
typedef struct conin_buffer_struct
{
unsigned char buffer[CONIO_BUFFER_SIZE];
size_t length;
} conio_buffer_t;
typedef struct typeahead_buffer_struct
{
unsigned char buffer[TYPEAHEAD_BUFFER_SIZE];
size_t length;
} typeahead_buffer_t;
static conio_buffer_t line_buffer, key_buffer;
static typeahead_buffer_t typeahead_buffer;
static int max_scancode_conversion_length = 0;
static unsigned char * keyboard_scancode_table[] = DEFAULT_SCANCODE_CONVERSIONS;
/* This is a kludge to save 200 bytes or so of memory; sigh! */
#ifndef ULONG_BIT
#define ULONG_BIT (sizeof(unsigned long)*CHAR_BIT)
#endif
#define MALLOCED_TABLE_SIZE \
((KEYBOARD_SCANCODE_TABLE_SIZE+(ULONG_BIT-1))/ULONG_BIT)
static unsigned long scancode_malloced_table[MALLOCED_TABLE_SIZE] = {0,};
#define Scancode_To_Malloced_Table_Word(s) ((s)/ULONG_BIT)
#define Scancode_To_Malloced_Table_Word_Bit(s) ((s)%ULONG_BIT)
#define Scancode_Malloced_p(s) \
(scancode_malloced_table[Scancode_To_Malloced_Table_Word(s)] & \
(1 << Scancode_To_Malloced_Table_Word_Bit(s)))
#define Scancode_Malloced(s) \
(scancode_malloced_table[Scancode_To_Malloced_Table_Word(s)] |= \
(1 << Scancode_To_Malloced_Table_Word_Bit(s)))
#define Scancode_Malloced_Not(s) \
(scancode_malloced_table[Scancode_To_Malloced_Table_Word(s)] &= \
(~(1 << Scancode_To_Malloced_Table_Word_Bit(s))))
/* End of Kludge */
#define Max(a, b) (((a) > (b)) ? (a) : (b))
#define Typeahead_Buffer_Remaining() \
(TYPEAHEAD_BUFFER_SIZE - typeahead_buffer.length)
#define Typeahead_Buffer_Available_p() \
(Typeahead_Buffer_Remaining() >= max_scancode_conversion_length)
static void
DEFUN (map_keyboard_scancode, (scancode), unsigned char scancode)
{ extern int signal_keyboard_character_interrupt(unsigned char);
if (scancode < KEYBOARD_SCANCODE_TABLE_SIZE)
{
int len;
unsigned char * conversion = keyboard_scancode_table[scancode];
if (conversion == NO_CONVERSION)
return;
len = ((conversion == CTRL_AT) ? 1 : strlen (conversion));
if (len <= (Typeahead_Buffer_Remaining ()))
{ /* Copy conversion string into typeahead buffer, worrying about
interrupt characters along the way. */
while (--len >= 0)
{
if ((signal_keyboard_character_interrupt (*conversion)) == 0)
typeahead_buffer.buffer[typeahead_buffer.length++] = *conversion++;
}
}
}
return;
}
static void
DEFUN_VOID (recompute_max_scancode_conversion_length)
{
int i, length;
max_scancode_conversion_length = 0;
for (i = 0; i < KEYBOARD_SCANCODE_TABLE_SIZE; i++)
{
unsigned char * conversion = keyboard_scancode_table[i];
if (conversion == NO_CONVERSION)
length = 0;
else if (conversion == CTRL_AT)
length = 1;
else
length = strlen (conversion);
max_scancode_conversion_length
= Max (length, max_scancode_conversion_length);
}
return;
}
static void
DEFUN_VOID (initialize_scancode_table)
{
recompute_max_scancode_conversion_length ();
}
DEFINE_PRIMITIVE ("KEYBOARD-GET-CONVERSION", Prim_keyboard_get_conversion,
1, 1, 0)
{
PRIMITIVE_HEADER (1);
{
long scancode = arg_integer(1);
if ((scancode < 0) || (scancode >= KEYBOARD_SCANCODE_TABLE_SIZE))
error_bad_range_arg(1);
else
{
unsigned char * conversion = keyboard_scancode_table[scancode];
if (conversion == NO_CONVERSION)
PRIMITIVE_RETURN (SHARP_F);
else if (conversion == CTRL_AT)
PRIMITIVE_RETURN (memory_to_string (1, "\0"));
else
PRIMITIVE_RETURN (char_pointer_to_string (conversion));
}
}
}
DEFINE_PRIMITIVE ("KEYBOARD-SET-CONVERSION!", Prim_keyboard_set_conversion,
2, 2, 0)
{
PRIMITIVE_HEADER (2);
{
int scancode = arg_integer (1);
SCHEME_OBJECT scheme_conversion = ARG_REF (2);
if ((scancode < 0) || (scancode >= KEYBOARD_SCANCODE_TABLE_SIZE))
error_bad_range_arg(1);
else
{
int len;
if ((scheme_conversion != SHARP_F)
&& (!STRING_P (scheme_conversion)))
error_wrong_type_arg (2);
if ((scheme_conversion == SHARP_F)
|| ((len = (STRING_LENGTH (scheme_conversion)))
== 0))
{
if (Scancode_Malloced_p (scancode))
DOS_free (keyboard_scancode_table[scancode]);
keyboard_scancode_table[scancode] = NO_CONVERSION;
Scancode_Malloced_Not (scancode);
}
else if ((len == 1)
&& ((STRING_REF (scheme_conversion, 0)) == '\0'))
{
if (Scancode_Malloced_p (scancode))
DOS_free (keyboard_scancode_table[scancode]);
keyboard_scancode_table[scancode] = CTRL_AT;
Scancode_Malloced_Not (scancode);
}
else
{
int i;
unsigned char * old_conversion
= keyboard_scancode_table[scancode];
unsigned char * conversion, * scheme;
conversion = (DOS_malloc (len + 1));
if (conversion == 0)
error_system_call (ENOMEM, syscall_malloc);
if (Scancode_Malloced_p (scancode))
DOS_free (old_conversion);
keyboard_scancode_table[scancode] = conversion;
Scancode_Malloced (scancode);
for (i = 0, scheme = (STRING_LOC (scheme_conversion, 0));
i <= len;
i ++)
*conversion++ = *scheme++;
*conversion = '\0';
}
recompute_max_scancode_conversion_length ();
PRIMITIVE_RETURN (UNSPECIFIC);
}
}
}
static void
DEFUN_VOID (consume_typeahead)
{
extern int signal_keyboard_character_interrupt(unsigned char);
unsigned char character;
while ( (Typeahead_Buffer_Available_p()) &&
(dos_poll_keyboard_character(&character)) )
{
if (character == '\0') /* Extended scancode */
{
dos_poll_keyboard_character(&character);
map_keyboard_scancode(character);
}
else if (signal_keyboard_character_interrupt(character) == 0)
typeahead_buffer.buffer[typeahead_buffer.length++] = character;
else
break;
}
return;
}
static int
DEFUN_VOID (typeahead_available_p)
{
consume_typeahead();
return !(typeahead_buffer.length == 0);
}
static unsigned char
DEFUN_VOID (get_typeahead_character)
{ unsigned char result;
if (typeahead_buffer.length == 0)
return '\0';
else
{ int i;
result = typeahead_buffer.buffer[0];
for (i = 1; i < typeahead_buffer.length; i++)
typeahead_buffer.buffer[i - 1] = typeahead_buffer.buffer[i];
typeahead_buffer.length--;
return result;
}
}
DEFINE_PRIMITIVE ("CONSUME-TYPEAHEAD", Prim_consume_typeahead, 0, 0,
"Suck up DOS typeahead.")
{
PRIMITIVE_HEADER(0);
consume_typeahead();
PRIMITIVE_RETURN (UNSPECIFIC);
}
static void
DEFUN (key_buffer_insert_self, (c), unsigned char c)
{
static unsigned char crlf[] = {CARRIAGE_RETURN, LINEFEED};
if (key_buffer.length != CONIO_BUFFER_SIZE)
{
key_buffer.buffer[key_buffer.length++] = c;
( (c == LINEFEED)
? dos_console_write(crlf, sizeof(crlf))
: dos_console_write(&c, 1) );
}
return;
}
static void
DEFUN_VOID (key_buffer_erase_character)
{
static char erase[] = {BACKSPACE, SPACE, BACKSPACE};
if (key_buffer.length != 0)
{
key_buffer.length -= 1;
dos_console_write(erase, sizeof(erase));
}
return;
}
static void
DEFUN_VOID(key_buffer_to_line_buffer)
{ register size_t i = 0;
register size_t j = 0;
while ((i < key_buffer.length)&&(line_buffer.length != CONIO_BUFFER_SIZE))
line_buffer.buffer[line_buffer.length++] = key_buffer.buffer[i++];
while (i < key_buffer.length)
key_buffer.buffer[j++] = key_buffer.buffer[i++];
key_buffer.length = j;
return;
}
void
DEFUN_VOID (flush_conio_buffers)
{
line_buffer.length = 0;
key_buffer.length = 0;
typeahead_buffer.length = 0;
return;
}
void
DEFUN_VOID (DOS_initialize_conio)
{ void initialize_keyboard_interrupt_table(void);
flush_conio_buffers();
initialize_keyboard_interrupt_table();
initialize_scancode_table();
return;
}
static int
DEFUN(empty_line_buffer, (buffer, nbytes), char * buffer AND size_t nbytes)
{ register size_t i, j;
for (i = 0; ((i < line_buffer.length)&&(i < nbytes)); i++)
*buffer++ = line_buffer.buffer[i];
nbytes = i;
for (j = 0; i < line_buffer.length; i++, j++)
line_buffer.buffer[j] = line_buffer.buffer[i];
line_buffer.length -= nbytes;
return nbytes;
}
static void
DEFUN (buffered_key_command, (c), unsigned char c)
{
switch(c)
{
case CARRIAGE_RETURN:
case LINEFEED:
key_buffer_insert_self(LINEFEED);
key_buffer_to_line_buffer();
break;
case DELETE:
case BACKSPACE: /* Backspace */
if (key_buffer.length != 0)
key_buffer_erase_character();
break;
default:
key_buffer_insert_self(c);
break;
}
return;
}
static void
DEFUN (non_buffered_key_command, (c), unsigned char c)
{
if (line_buffer.length == CONIO_BUFFER_SIZE) return;
if ((!DOS_keyboard_intercepted_p)
&& (c == BACKSPACE))
c = DELETE;
line_buffer.buffer[line_buffer.length++] = c;
return;
}
long
DEFUN(console_read, (buffer, nbytes, buffered_p, blocking_p),
char * buffer AND unsigned nbytes AND int buffered_p AND int blocking_p)
{
System_Error_Reset();
do
{ /* Get all pending characters into the buffer */
while (typeahead_available_p())
{
if (buffered_p)
buffered_key_command(get_typeahead_character());
else /* Non buffered channel, in CScheme, also no echo. */
non_buffered_key_command(get_typeahead_character());
} /* End WHILE */
/* Test for pending interrupts here: */
if (pending_interrupts_p())
{ if (INTERRUPT_QUEUED_P(INT_Character))
flush_conio_buffers();
System_Error_Return(EINTR);
}
/* Return if we buffered up a line, or channel is not buffered */
if (line_buffer.length != 0)
return empty_line_buffer(buffer, nbytes);
} while (blocking_p); /* Keep reading for blocking channel. */
/* This means there is nothing available, don't block */
System_Error_Return(ERRNO_NONBLOCK);
}
extern int EXFUN
(text_write, (int fd AND CONST unsigned char * buffer AND size_t nbytes));
void
DEFUN (console_write_string, (string), void * string)
{
text_write(fileno(stdout), string, strlen((char *) string));
return;
}